# Tem IRC Bot 0.3
# Requirements: Ruby 1.9+. Ruby Gems module
#  http://code.google.com/p/temirc/

# MAIN INCLUDES
require "includes.tem.rb"
require "tem.config.rb"
require "class_irc.rb"
require "class_module.rb"
require "func_builtin.rb"


class Tem
	def initialize()
	# This is a kinda future proofing towards multiple server support.
		@password = $password
		@host = $hostname
		@port = $port
		@nick = $nick
		@fallback_nick = $fallback_nick
		@ident_1 = $ident1
		@ident_2 = $ident2
		@realname = $realname
		@channels = $channels
		@auth_hosts = []
	end

	def connect() 
		begin
			if $bind_address.length > 2
				@socket_handle = TCPSocket.open(@host, @port, $bind_address)
			else
				@socket_handle = TCPSocket.open(@host, @port)
			end

			@command_handler = IRCCommands.new(@socket_handle)
			@modules_handler = Modules.new(@command_handler)
		rescue
			prnt "[Core] Error Connecting to server: #{@host} on port #{@port}"
		end

		# Check socket created successfully.
                if !@socket_handle
                        prnt "[Core] Error creating socket! check server/socket details!"
                        exit
                end

		# Send the User details to the server.
		@socket_handle.print "NICK #{@nick}\r\n"
		@socket_handle.print "USER #{@ident_1} 8 * :#{@ident_2} #{@realname}\r\n"
	end

	def authed?(host)
		return @auth_hosts.include?(host)
	end
	
	def parse()
		while @parser_cur_line = @socket_handle.gets
			if @parser_cur_line =~ /PING/
				@command_handler.send_pong(@parser_cur_line)
				prnt "PING Recieved, Sent PONG."
			elsif @parser_cur_line =~ /PRIVMSG/
					# Always handle PRIVMSG first, incase of containers.
					# Lets seperate the msg from the command.
					priv_msg = @parser_cur_line.split(" ")
					# Strip the : 
					priv_msg[3][0] = ""
					if priv_msg[3] =~ /^\./ # Possible command
						command_parameters = priv_msg[4,priv_msg.length - 1].join(" ")
						priv_msg[3][0] = "" # Strip the . from the command.
						command = priv_msg[3]
						subject = priv_msg[2]
						if command != "login" # Dont log passwords.
							prnt "Command Recieved: #{command} Command Parameters: #{command_parameters}"
						end
						# Small builtin commands.
						if command == "hi"
								@command_handler.privmsg(subject, "Hi!")
						elsif command == "quit"
								@command_handler.privmsg(subject, "Exiting Gracefully..")
								@command_handler.quit_msg("Byeeee From Tem :D")
								break;
						elsif command == "do"
								@command_handler.action(subject, command_parameters)
						elsif command == "load"
								@command_handler.privmsg(subject, "Attempting to load module...")
								@modules_handler.dynamic_load(command_parameters, subject)
						elsif command == "login"
							# Added login routine for 0.4, sets up some basic auth.
								@command_handler.privmsg(subject, "Attempting to login..")
								pass = priv_msg[4]
								if Digest::MD5.hexdigest(pass) == @password
									# Password is correct.
									@command_handler.privmsg(subject, "Login correct.")
									host = getAuthHost(priv_msg[0])
									@auth_hosts.push(host)
								else 
									@command_handler.privmsg(subject, "Login incorrect.")
								end
						elsif command == "loginstatus" # Example auth status command.
								host = getAuthHost(priv_msg[0])
								if @auth_hosts.include?(host)
									@command_handler.privmsg(subject, "Login status: Logged in.")
								else 
									@command_handler.privmsg(subject, "Login status: Not logged in.")
								end
						end
						# Handover to Modules to parse.
						@modules_handler.parse_to_module(command, command_parameters, subject, authed?(getAuthHost(priv_msg[0])))
					else
						full_cmd = priv_msg[3,priv_msg.length - 1].join(" ")
						prnt "Message Recieved: #{full_cmd}"
					end
			# Use nick fallback if nick is in use (prevents connection)
			elsif @parser_cur_line =~ /433[\s](\*)?[\s]+#{@nick}[\s]+(\:)?/
					@socket_handle.print "NICK #{@fallback_nick}\r\n"
					@socket_handle.print "USER #{@ident_1} 8 * :#{@ident_2} #{@realname}\r\n"
					# For this run, change @nick to the @fallback_nick for bot to keep going.
					@nick = @fallback_nick
			# Connection Information parser.
			elsif @parser_cur_line =~ /00(1|2|3|4|5)[\s]+#{@nick}[\s]+(\:)?/ # Seems plausibly the messages.
					# The 00# numbers can give us a sure server real hostname, we'll use 002 to grab it.
					if @parser_cur_line =~ /002[\s]#{@nick}[\s]\:/ 
						real_host = @parser_cur_line.split(/002/)
						real_host[0][0] = ""; # Chop off the : at the start of the host.
						@server_real_host = real_host[0];
					end
			# Second Connection Information parser.
			elsif @parser_cur_line =~ /(2(5(1|2|4|5|0)|6(5|6))|439|931|042)[\s]+#{@nick}[\s]+(\:)?/ # Some IRCds spit out some weird codes.
					# Check for certain ones that dont use a :
					if @parser_cur_line =~ /#{@nick}[\s]\:/
						connect_info = @parser_cur_line.split(/#{@nick}[\s]\:/);
					else
						connect_info = @parser_cur_line.split(/#{@nick}/);
					end
					prnt "Server Information Recieved: #{connect_info[1]}"
			# MOTD Parser
			elsif @parser_cur_line =~ /375[\s]+#{@nick}[\s]+\:/ 
					# Create own loop to grab entire MOTD before letting main loop continue.
					@motd = "";
					prnt "Processing MOTD.."
					while @parser_cur_line = @socket_handle.gets
						# Check for end of MOTD.
						if @parser_cur_line =~ /376[\s]+#{@nick}[\s]+\:/ 
							break # Return control to main loop.
						end
						# Process each @parser_cur_line of the MOTD.
						if @parser_cur_line =~ /372[\s]+#{@nick}[\s]+\:/ 
							@motd = @motd + @parser_cur_line # Add the @parser_cur_line to the MOTD global string.	
						end
					end
					prnt "MOTD Parsed successfully."
					# Put in the call to join a channel now connection seems clear.
					@channels.each do |channel|
						@command_handler.join(channel)
					end	
			elsif @parser_cur_line =~ /422/ # Deal with "MOTD file is missing."
					prnt "MOTD File seems to be missing from server.. continung.."
					@channels.each do |channel|
						@command_handler.join(channel)
					end	
			# Connection NOTICE parser.
			elsif @parser_cur_line =~ /NOTICE/
					if @parser_cur_line =~ /NOTICE[\s]+(AUTH|Auth)([\s]\:)?/
						notice = @parser_cur_line.split(/(Auth|AUTH)[\s]\:/);
						prnt "Auth Notice Recieved: #{notice[2]}"
					else
						notice = @parser_cur_line.split(/NOTICE[\s]+#{@nick}[\s]+\:/);
						prnt "Notice recieved: #{notice[1]}" 
					end
			# Unknown @parser_cur_line? just protocol info?
			else 
				prnt @parser_cur_line.chop 
			end
		end
	prnt("Exit")
	end
end


# Handle the forking.
if $daemonize == 1
	$pid = fork do
		Signal.trap('HUP', 'IGNORE')
		# Setup the connection.
		server_handle = Tem.new()
		server_handle.connect()
		server_handle.parse()
	end
else
	# Setup the connection.
	server_handle = Tem.new()
	server_handle.connect()
	server_handle.parse()
end

# Daemonize if needed.
if $pid
	Process.detach($pid)
end

